﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DiscoveryLogic.Common.Numeric
{
    [Serializable]
    public abstract class AbstractDistribution : PersistentObject, DoubleFunction, IntFunction, ICloneable
    {
        protected internal RandomEngine randomGenerator;
        /// <summary> Makes this class non instantiable, but still let's others inherit from it.</summary>
        protected internal AbstractDistribution()
        {
        }
        /// <summary>Equivalent to <tt>nextDouble()</tt>.
        /// This has the effect that distributions can now be used as function objects, returning a random number upon function evaluation.
        /// </summary>
        public virtual double apply(double dummy)
        {
            return nextDouble();
        }
        /// <summary>Equivalent to <tt>nextInt()</tt>.
        /// This has the effect that distributions can now be used as function objects, returning a random number upon function evaluation.
        /// </summary>
        public virtual int apply(int dummy)
        {
            return nextInt();
        }
        /// <summary> Returns a deep copy of the receiver; the copy will produce identical sequences.
        /// After this call has returned, the copy and the receiver have equal but separate state.
        /// 
        /// </summary>
        /// <returns> a copy of the receiver.
        /// </returns>
        public override System.Object Clone()
        {
            AbstractDistribution copy = (AbstractDistribution)base.Clone();
            if (this.randomGenerator != null)
                copy.randomGenerator = (RandomEngine)this.randomGenerator.Clone();
            return copy;
        }
        /// <summary> Returns the used uniform random number generator;</summary>
        protected internal virtual RandomEngine getRandomGenerator()
        {
            return randomGenerator;
        }
        /// <summary> Constructs and returns a new uniform random number generation engine seeded with the current time.
        /// Currently this is {@link cern.jet.random.engine.MersenneTwister}.
        /// </summary>
        public static RandomEngine makeDefaultGenerator()
        {
            return RandomEngine.makeDefault();
        }
        /// <summary> Returns a random number from the distribution.</summary>
        public abstract double nextDouble();
        /// <summary> Returns a random number from the distribution; returns <tt>(int) Math.round(nextDouble())</tt>.
        /// Override this method if necessary.
        /// </summary>
        public virtual int nextInt()
        {
            //UPGRADE_TODO: Method 'java.lang.Math.round' was converted to 'System.Math.Round' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangMathround_double'"
            return (int)System.Math.Round(nextDouble());
        }
        /// <summary> Sets the uniform random generator internally used.</summary>
        protected internal virtual void setRandomGenerator(RandomEngine randomGenerator)
        {
            this.randomGenerator = randomGenerator;
        }
    }
}
